<?php

namespace app\admin\service;

use app\admin\model\Abnormal;
use app\admin\model\Operation;
use app\admin\model\Street;
use app\admin\model\User;

/**
 * 打标作业
 */
class OperationService
{
    /**
     * @var Operation
     */
    private $model;

    public function __construct()
    {
        $this->model = new Operation;
    }

    public function lists(array $param, $userId): array
    {
        $query = $this->model
            ->where('mark', 1)
            ->where('type', $param['type'])
            ->with(
                [
                    'unit' => function ($query) {
                        $query->field('id, unit_name');
                    },
                    'user' => function ($query) {
                        $query->field('id, realname');
                    }
                ]
            );
        $user = User::find($userId);
        if (!empty($user->auth) && $user->auth != 'all') {
            $query->whereIn('exception_category', explode(',', $user->auth));
        }
        if (empty($param['notGroup'])) {
            $query->group('operation_no');
            $field = [
                'min(id) id',
                'operation_no',
                'organization_id',
                'create_user',
                'create_time',
                'group_concat(operation_category) operation_category',
                'group_concat(exception_category) exception_category',
                'group_concat(organization_show) organization_show',
                'group_concat(penalty) penalty',
                'group_concat(address) address',
                'group_concat(verify_user) verify_user',
                'group_concat(verify_user_list, "+") verify_user_list'
            ];
        } else {
            $field = ['*'];
        }
        if (!empty($param['operation_no'])) {
            $query->where('operation_no', 'like', '%' . $param['operation_no'] . '%');
        }
        if (!empty($param['organization_id'])) {
            $query->where('organization_id', $param['organization_id']);
        }
        if (!empty($param['operation_category'])) {
            $query->where('operation_category', $param['operation_category']);
        }
        if (!empty($param['exception_category'])) {
            $query->where('exception_category', $param['exception_category']);
        }
        if (!empty($param['area_id'])) {
            $query->where('area_id', end($param['area_id']));
        }
        if (isset($param['organization_show']) && is_numeric($param['organization_show'])) {
            $query->where('organization_show', $param['organization_show']);
        }
        if (isset($param['penalty']) && is_numeric($param['penalty'])) {
            $query->where('penalty', $param['penalty']);
        }
        if (!empty($param['create_user'])) {
            $userIds = User::where('name', 'like', '%' . $param['create_user'] . '%')->column('id');
            $query->whereIn('create_user', $userIds);
        }
        if (!empty($param['date'])) {
            $query->where('create_time', 'between', array_map('strtotime', $param['date']));
        }
        if (!empty($param['address'])) {
            $query->whereLike('address', "%" . $param['address'] . "%");
        }
        if (!empty($param['time'])) {
            $start_time = strtotime($param['time'][0]);
            $end_time   = strtotime($param['time'][1]) + 3600 * 24 - 1;
            $query->whereBetween('create_time', [$start_time, $end_time]);
        }
        if (!empty($param['lnglat'])) {
            $query->where('longitude', 'between', [$param['lnglat'][0] - 0.0004, $param['lnglat'][0] + 0.0004]);
            $query->where('latitude', 'between', [$param['lnglat'][1] - 0.0004, $param['lnglat'][1] + 0.0004]);
        }
        $data = [
            'msg'   => 'success',
            'code'  => 0,
            'data'  => [],
            'count' => (clone $query)->count('id'),
        ];
        if ($data['count']) {
            $data['data']      = $query->order('id', 'desc')
                ->page(PAGE, PERPAGE)
                ->field($field)
                ->select()
                ->toArray();
            $exceptionCategory = [];
            $userIds           = [];
            foreach ($data['data'] as &$val) {
                $exceptionCategory = array_merge($exceptionCategory, explode(',', $val['exception_category']));
                $verifyUserListTemp = explode('+', $val['verify_user_list']);
                $verifyUserList     = [];
                foreach ($verifyUserListTemp as $v) {
                    $v = $v ? json_decode($v, true) : [];
                    foreach ($v as $vv) {
                        $userIds[]        = $vv;
                        $verifyUserList[] = $vv;
                    }
                }
                $val['verify_user_list'] = array_unique($verifyUserList);
            }
            unset($val);
            $exceptionCategory = Abnormal::where('id', 'in', $exceptionCategory)->column('name', 'id');
            if ($userIds) {
                $users = User::where('id', 'in', $userIds)->column('realname', 'id');
            }

            foreach ($data['data'] as &$item) {
                $item['organization_name'] = $item['unit']['unit_name'];
                $item['create_user']       = $item['user']['realname'];
                if (empty($param['notGroup'])) {
                    $item['address']            = str_replace(',', '/', $item['address']);
                    $item['organization_show']  = array_map(
                        'intval',
                        array_unique(explode(',', $item['organization_show']))
                    );
                    $item['penalty']            = array_map('intval', array_unique(explode(',', $item['penalty'])));
                    $item['operation_category'] = explode(',', $item['operation_category']);
                    $item['exception_category'] = explode(',', $item['exception_category']);
                    foreach ($item['operation_category'] as &$v) {
                        $v = $this->model->getOperationCategoryNameAttr('', ['operation_category' => $v]);
                    }
                    unset($v);
                    foreach ($item['exception_category'] as &$v) {
                        $v = $exceptionCategory[$v] ?? '';
                    }
                    unset($v);
                    $item['operation_category_name'] = implode(',', array_unique($item['operation_category']));
                    $item['exception_category_name'] = implode(',', array_unique($item['exception_category']));
                    if ($param['type'] == 'illegal') {
                        $item['verify_user'] = explode(',', $item['verify_user']);
                        foreach ($item['verify_user'] as $k => $v) {
                            $item['is_verify'][$k] = $v ? 1 : 0;
                        }
                        $item['verify_user_name'] = [];
                        foreach ($item['verify_user_list'] as $v) {
                            if (!empty($users[$v])) {
                                $item['verify_user_name'][] = $users[$v];
                            }
                        }
                        $item['is_verify']        = array_unique($item['is_verify']);
                        $item['verify_user_name'] = implode(',', array_unique($item['verify_user_name']));
                    }
                } else {
                    $item['operation_category_name'] = $this->model->getOperationCategoryNameAttr(
                        '',
                        ['operation_category' => $item['operation_category']]
                    );
                    $item['exception_category_name'] = $exceptionCategory[$item['exception_category']] ?? '';
                    $item['is_verify']               = $item['verify_user'] ? 1 : 0;
                    $item['images']                  = $item['images'] ? json_decode($item['images'], true) : [];
                }
                unset($item['unit']);
            }
        }

        return $data;
    }

    public function info($operationNo): array
    {
        $data    = $this->model
            ->with(
                [
                    'unit'     => function ($query) {
                        $query->field('id, unit_name');
                    },
                    'abnormal' => function ($query) {
                        $query->field('id, name');
                    },
                    'user'     => function ($query) {
                        $query->field('id, realname');
                    },
                    'readUser'
                ]
            )
            ->where('mark', 1)
            ->where('operation_no', $operationNo)
            ->order('id', 'desc')
            ->select();
        $userIds = [];
        foreach ($data as &$val) {
            $val['verify_user_list'] = $val['verify_user_list'] ? json_decode($val['verify_user_list'], true) : [];
            $userIds                 = array_merge($userIds, $val['verify_user_list']);
        }
        unset($val);
        $users = User::where('id', 'in', $userIds)->column('realname', 'id');

        foreach ($data as &$val) {
            $val['organization_name']       = $val['unit']['unit_name'];
            $val['exception_category_name'] = $val['abnormal']['name'];
            $val['create_user']             = $val['user']['realname'];
            $val['operation_category_name'] = $val['operation_category_name'];
            $val['images']                  = $val['images'] ? json_decode($val['images'], true) : [];
            $val['diff_points']             = $val['diff_points'] ? json_decode($val['diff_points'], true) : [];
            $val['credential']              = $val['credential'] ? json_decode($val['credential'], true) : [];
            $val['area_id']                 = [
                (substr($val['area_id'], 0, 2)),
                (substr($val['area_id'], 0, 4)),
                (string)$val['area_id']
            ];
            if ($val['type'] === 'illegal') {
                $verifyUserName = [];
                foreach ($val['verify_user_list'] as $v) {
                    $verifyUserName[] = $users[$v] ?? '';
                }
                $val['verify_user_name'] = implode(',', $verifyUserName);
                $val['is_verify']        = $val['verify_user'] ? 1 : 0;
            }
        }

        return $data->toArray();
    }

    public function save($param, $userId)
    {
        if (empty($param['id'])) {
            if (empty($param['operation_no'])) {
                $param['operation_no'] = $this->getOperationNo($param['type']);
            }
            $param['create_user'] = $userId;
        } else {
            $param['update_user'] = $userId;
        }
        $street                    = (new Street)->getInfoByGrid($param['longitude'], $param['latitude'], ['id']);
        $param['street_id']        = $street->id ?? 0;
        $param['area_id']          = end($param['area_id']);
        $param['images']           = json_encode($param['images']);
        $param['verify_user_list'] = json_encode($param['verify_user_list']);

        $saveData = [$param];
        if (!empty($param['id'])) {
            $saveData[] = ['id' => $param['id']];
        }
        $this->model->allowField(true)->save(...$saveData);

        return $param['operation_no'];
    }

    /**
     * @throws \Exception
     */
    public function add($param, $userId)
    {
        $street   = (new Street)->getInfoByGrid($param['longitude'], $param['latitude'], ['id']);
        $saveData = [];
        foreach ($param['module'] as $module) {
            $saveData[] = [
                'type'               => $module['type'],
                'operation_no'       => $this->getOperationNo($module['type']),
                'organization_id'    => $module['organization_id'],
                'exception_category' => $module['exception_category'],
                'verify_user_list'   => json_encode($module['verify_user_list']),
                'operation_category' => $param['operation_category'],
                'address'            => $param['address'],
                'organization_show'  => $param['organization_show'],
                'penalty'            => $param['penalty'],
                'description'        => $param['description'],
                'loitering_times'    => $param['loitering_times'],
                'loitering_duration' => $param['loitering_duration'],
                'loitering_distance' => $param['loitering_distance'],
                'longitude'          => $param['longitude'],
                'latitude'           => $param['latitude'],
                'images'             => json_encode($param['images']),
                'diff_points'        => json_encode($param['diff_points']),
                'area_id'            => end($param['area_id']),
                'street_id'          => $street->id ?? 0,
                'create_user'        => $userId,
                'update_user'        => $userId
            ];
        }

        return count($this->model->allowField(true)->saveAll($saveData));
    }

    public function setShow($id)
    {
        if (is_array($id)) {
            $query = $this->model->where('operation_no', 'in', $id);
        } else {
            $query = $this->model->where('operation_no', $id);
        }
        $query->update(['organization_show' => 1]);
    }

    public function getPushUser($id)
    {
//        $userIds = $this->model->where('id', $id)->value('verify_user_list');
//        return User::whereIn('id',  json_decode($userIds, true))->select();
        return User::where('mark', 1)->select();
    }

    public function pushMsg($id, $userIds)
    {
        $operation = $this->model->where('id', $id)->find();
        $users     = User::whereIn('id', $userIds)->field('id, openid, realname')->select();
        $data = [];
        foreach ($users as $user) {
            $param = [
                'touser'      => $user['openid'],
                'template_id' => 'MiQsc47xJVf-F8jnR-PwuVwkgphDElufNPL9PS9wnFY',
                'miniprogram' => [
                    'appid'    => 'wx0bef957dc85f8fbb',
                    'pagepath' => 'pages/index/taskDetailReadonly?id=' . ($id . '_' . $user['id'])
                ],
                'data'        => [
                    'thing2' => [
                        'value' => mb_substr($operation['address'], 0, 20),
                    ],
                    'time4'  => [
                        'value' => date('Y年m月d日 H:i:s', strtotime($operation['create_time'])),
                    ],
                    'thing5' => [
                        'value' => $operation['operation_category_name'],
                    ]
                ]
            ];
            try {
                (new WechatService)->sendTplMsg($param);
                $msg = '推送成功';
            } catch (\Exception $e) {
                $msg = $e->getCode() == '43004' ? '没有关注该服务号' : $e->getMessage();
            }
            $data[] = [
                'user' => $user['realname'],
                'msg' => $msg
            ];
        }

        return $data;
    }


    public function delete($id, $field)
    {
        if (is_array($id)) {
            $query = $this->model->where($field, 'in', $id);
        } else {
            $query = $this->model->where($field, $id);
        }
        $query->update(['mark' => 0]);
    }

    public function groupStreet($exceptionCategory, $date): array
    {
        $data = $this->model->fieldRaw('street_id, count(id) total')
            ->whereIn('exception_category', $exceptionCategory)
            ->whereBetween('create_time', $date)
            ->group('street_id')
            ->select()
            ->toArray();

        return array_column($data, 'total', 'street_id');
    }

    private function getOperationNo($type): string
    {
        $arr = [
            'emergency'  => 'YG',
            'way'        => 'ON',
            'protection' => 'HB',
            'illegal'    => 'WJ'
        ];

        return ($arr[$type] ?? 'OT') . strtoupper(uniqid());
    }
}
